package cn.heyige.backend.algorithm;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

/**
 * 真太阳时计算器
 * 提供更精确的真太阳时计算和缓存机制
 */
public class SolarTimeCalculator {

    // 中国标准时间的经度（东经120度）
    private static final double CHINA_STANDARD_LONGITUDE = 120.0;

    // 城市经度缓存
    private static final Map<String, Double> CITY_LONGITUDE_CACHE = new HashMap<>();

    // 太阳时偏差缓存（日期+经度 -> 偏差分钟）
    private static final Map<String, Integer> SOLAR_TIME_OFFSET_CACHE = new HashMap<>();

    static {
        CITY_LONGITUDE_CACHE.put("北京", 116.4);
        CITY_LONGITUDE_CACHE.put("上海", 121.5);
        CITY_LONGITUDE_CACHE.put("广州", 113.3);
        CITY_LONGITUDE_CACHE.put("深圳", 114.1);
        CITY_LONGITUDE_CACHE.put("重庆", 106.5);
        CITY_LONGITUDE_CACHE.put("成都", 104.1);
        CITY_LONGITUDE_CACHE.put("杭州", 120.2);
        CITY_LONGITUDE_CACHE.put("武汉", 114.3);
        CITY_LONGITUDE_CACHE.put("西安", 108.9);
        CITY_LONGITUDE_CACHE.put("天津", 117.2);
        CITY_LONGITUDE_CACHE.put("南京", 118.8);
        CITY_LONGITUDE_CACHE.put("沈阳", 123.4);
        CITY_LONGITUDE_CACHE.put("大连", 121.6);
        CITY_LONGITUDE_CACHE.put("青岛", 120.4);
        CITY_LONGITUDE_CACHE.put("厦门", 118.1);
        CITY_LONGITUDE_CACHE.put("苏州", 120.6);
        CITY_LONGITUDE_CACHE.put("济南", 117.0);
        CITY_LONGITUDE_CACHE.put("长沙", 112.9);
        CITY_LONGITUDE_CACHE.put("郑州", 113.6);
        CITY_LONGITUDE_CACHE.put("合肥", 117.3);
        CITY_LONGITUDE_CACHE.put("昆明", 102.7);
        CITY_LONGITUDE_CACHE.put("哈尔滨", 126.6);
        CITY_LONGITUDE_CACHE.put("长春", 125.3);
        CITY_LONGITUDE_CACHE.put("南昌", 115.9);
        CITY_LONGITUDE_CACHE.put("太原", 112.5);
        CITY_LONGITUDE_CACHE.put("福州", 119.3);
        CITY_LONGITUDE_CACHE.put("南宁", 108.3);
        CITY_LONGITUDE_CACHE.put("海口", 110.3);
        CITY_LONGITUDE_CACHE.put("贵阳", 106.7);
        CITY_LONGITUDE_CACHE.put("兰州", 103.8);
        CITY_LONGITUDE_CACHE.put("西宁", 101.8);
        CITY_LONGITUDE_CACHE.put("银川", 106.3);
        CITY_LONGITUDE_CACHE.put("乌鲁木齐", 87.6);
        CITY_LONGITUDE_CACHE.put("呼和浩特", 111.7);
        CITY_LONGITUDE_CACHE.put("石家庄", 114.5);
        CITY_LONGITUDE_CACHE.put("保定", 115.5);
        CITY_LONGITUDE_CACHE.put("唐山", 118.2);
        CITY_LONGITUDE_CACHE.put("温州", 120.7);
        CITY_LONGITUDE_CACHE.put("东莞", 113.8);
        CITY_LONGITUDE_CACHE.put("佛山", 113.1);
        CITY_LONGITUDE_CACHE.put("珠海", 113.5);
        CITY_LONGITUDE_CACHE.put("中山", 113.4);
        CITY_LONGITUDE_CACHE.put("汕头", 116.7);
        CITY_LONGITUDE_CACHE.put("烟台", 121.4);
        CITY_LONGITUDE_CACHE.put("潍坊", 119.1);
        CITY_LONGITUDE_CACHE.put("济宁", 116.6);
        CITY_LONGITUDE_CACHE.put("徐州", 117.2);
        CITY_LONGITUDE_CACHE.put("洛阳", 112.4);
        CITY_LONGITUDE_CACHE.put("绵阳", 104.7);
        CITY_LONGITUDE_CACHE.put("芜湖", 118.4);
        CITY_LONGITUDE_CACHE.put("嘉兴", 120.8);
        CITY_LONGITUDE_CACHE.put("绍兴", 120.6);
        CITY_LONGITUDE_CACHE.put("湖州", 119.8);
        CITY_LONGITUDE_CACHE.put("金华", 119.6);
        CITY_LONGITUDE_CACHE.put("衢州", 118.9);
        CITY_LONGITUDE_CACHE.put("舟山", 122.1);
        CITY_LONGITUDE_CACHE.put("台州", 121.4);
        CITY_LONGITUDE_CACHE.put("宁波", 121.6);
        CITY_LONGITUDE_CACHE.put("拉萨", 91.1);
        CITY_LONGITUDE_CACHE.put("香港", 114.2);
        CITY_LONGITUDE_CACHE.put("澳门", 113.5);
    }

    /**
     * 计算真太阳时偏差（分钟）
     *
     * @param dateTime  日期时间
     * @param longitude 经度
     * @return 真太阳时偏差（分钟）
     */
    private static int calculateSolarTimeOffset(LocalDateTime dateTime, double longitude) {
        // 生成缓存键
        String cacheKey = dateTime.toLocalDate().toString() + ":" + longitude;
        // 检查缓存
        if (SOLAR_TIME_OFFSET_CACHE.containsKey(cacheKey)) {
            return SOLAR_TIME_OFFSET_CACHE.get(cacheKey);
        }
        // 计算经度偏差导致的时间差（每经度4分钟）
        double longitudeOffset = (longitude - CHINA_STANDARD_LONGITUDE) * 4;
        // 计算日期方程（简化版）
        int dayOfYear = dateTime.getDayOfYear();
        double equationOfTime = calculateEquationOfTime(dayOfYear);
        // 总偏差（分钟）
        int offset = (int) Math.round(longitudeOffset + equationOfTime);
        // 缓存结果（30分钟有效期，这里简化处理，实际应该有定时清理机制）
        SOLAR_TIME_OFFSET_CACHE.put(cacheKey, offset);
        return offset;
    }

    /**
     * 计算日期方程（改进版）
     *
     * @param dayOfYear 一年中的第几天
     * @return 日期方程值（分钟）
     */
    private static double calculateEquationOfTime(int dayOfYear) {
        // 改进的日期方程计算，更精确
        double b = 2 * Math.PI * (dayOfYear - 81) / 365.2422;
        return 0.000075 + 0.001868 * Math.cos(b) - 0.032077 * Math.sin(b)
                - 0.014615 * Math.cos(2 * b) - 0.040849 * Math.sin(2 * b);
    }


    /**
     * 根据出生地经度调整时间
     *
     * @param dateTime      原始日期时间
     * @param birthLocation 出生地（格式：城市名或经度值）
     * @return 调整后的日期时间
     */
    public static LocalDateTime adjustTimeByLocation(LocalDateTime dateTime, String birthLocation) {
        // 获取经度
        double longitude = extractLongitude(birthLocation);
        // 计算偏差（分钟）
        int offsetMinutes = calculateSolarTimeOffset(dateTime, longitude);
        // 调整时间
        return dateTime.plusMinutes(offsetMinutes);
    }

    /**
     * 从位置信息中提取经度
     *
     * @param location 位置信息
     * @return 经度值
     */
    private static double extractLongitude(String location) {
        if (location == null || location.isEmpty()) {
            return CHINA_STANDARD_LONGITUDE;
        }

        // 检查是否是城市名
        if (CITY_LONGITUDE_CACHE.containsKey(location)) {
            return CITY_LONGITUDE_CACHE.get(location);
        }

        // 尝试直接解析为经度值
        try {
            return Double.parseDouble(location);
        } catch (NumberFormatException e) {
            // 如果不是数字，返回默认经度
            return CHINA_STANDARD_LONGITUDE;
        }
    }

    /**
     * 添加城市经度数据
     *
     * @param city      城市名
     * @param longitude 经度
     */
    public static void addCityLongitude(String city, double longitude) {
        CITY_LONGITUDE_CACHE.put(city, longitude);
    }

    /**
     * 清除太阳时偏差缓存
     */
    public static void clearSolarTimeOffsetCache() {
        SOLAR_TIME_OFFSET_CACHE.clear();
    }
}